﻿#include "TcpServer.h"
#include "ui_TcpServer.h"

#include "QToolButton"

#include <QMenu>
#include <QMenuBar>
#include <QToolBar>

TcpServer::TcpServer(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::TcpServer)
{
    ui->setupUi(this);

    initUi();
}

TcpServer::~TcpServer()
{
    delete ui;
}

void TcpServer::initUi()
{
    // 菜单栏
    QToolBar *tbTop  = new QToolBar("TopBar", this);
    // tbTop->setIconSize(QSize(16, 16));

    // 初始放在顶部
    addToolBar(Qt::TopToolBarArea, tbTop);

    // 允许用户拖动
    tbTop->setMovable(true);
    // 允许拖出来变成独立浮动窗口
    tbTop->setFloatable(true);

    // 上下左右四个方向都能停靠
    tbTop->setAllowedAreas(Qt::AllToolBarAreas);

    /* 4. 随便放点 action，让工具栏有点东西 ------------------------------- */
    startListenAct = new QAction(QStringLiteral("开始监听"),  this);
    stopListenAct = new QAction(QStringLiteral("停止监听"),  this);
    clearAct = new QAction(QStringLiteral("清空文本框"), this);
    quitAct = new QAction(QStringLiteral("退出"), this);
    tbTop->addAction(startListenAct);
    tbTop->addAction(stopListenAct);
    tbTop->addAction(clearAct);
    tbTop->addAction(quitAct);

    // connect
    connect(startListenAct, &QAction::triggered, this, &TcpServer::onStartListenAct);
    connect(stopListenAct, &QAction::triggered, this, &TcpServer::onStopListenAct);
    connect(clearAct, &QAction::triggered, this, &TcpServer::onClearAct);
    connect(quitAct, &QAction::triggered, this, &TcpServer::onQuitAct);

    labListen = new QLabel(QStringLiteral("监听状态:"));
    labListen->setMinimumWidth(150);
    ui->statusbar->addWidget(labListen);

    labSocketState = new QLabel(QStringLiteral("Socket状态:"));
    labSocketState->setMinimumWidth(200);
    ui->statusbar->addWidget(labSocketState);

    // 本机Ip
    QString localIp = getLocalIp();

    this->setWindowTitle(this->windowTitle() + QStringLiteral("-----本机IP:") + localIp);

    ui->ipCombo->addItem(localIp);
    tcpServer = new QTcpServer(this);

    connect(tcpServer, &QTcpServer::newConnection, this, &TcpServer::onNewConnection);
}


QString TcpServer::getLocalIp()
{
    // 获取本机IPv4地址
    QString hostName = QHostInfo::localHostName();
    QHostInfo hostInfo = QHostInfo::fromName(hostName);
    QString localIp = "";
    QList<QHostAddress> addrList = hostInfo.addresses();
    if(!addrList.isEmpty())
        for (int i = 0; i < addrList.count(); i++) {
            QHostAddress aHost = addrList.at(i);
            if(QAbstractSocket::IPv4Protocol == aHost.protocol())
            {
                localIp = aHost.toString();
                break;
            }
        }
    return localIp;
}

void TcpServer::closeEvent(QCloseEvent *event)
{

}

void TcpServer::onNewConnection()
{
    // 获取socket
    tcpSocket = tcpServer->nextPendingConnection();
    onClientConnected();

    connect(tcpSocket, &QTcpSocket::disconnected, this, &TcpServer::onClientDisconnected);

    connect(tcpSocket, &QTcpSocket::stateChanged, this, &TcpServer::onSocketStateChange);

    onSocketStateChange(tcpSocket->state());

    connect(tcpSocket, &QTcpSocket::readyRead, this, &TcpServer::onSocketReadyRead);
}

void TcpServer::onSocketStateChange(QAbstractSocket::SocketState socketState)
{
    // socket状态变化
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState  :
        labSocketState->setText(QStringLiteral("socket状态:UnconnectedState"));
        break;
    case QAbstractSocket::HostLookupState   :
        labSocketState->setText(QStringLiteral("socket状态:HostLookupState"));
        break;
    case QAbstractSocket::ConnectingState   :
        labSocketState->setText(QStringLiteral("socket状态:ConnectingState"));
        break;
    case QAbstractSocket::ConnectedState    :
        labSocketState->setText(QStringLiteral("socket状态:ConnectedState"));
        break;
    case QAbstractSocket::BoundState        :
        labSocketState->setText(QStringLiteral("socket状态:BoundState"));
        break;
    case QAbstractSocket::ListeningState    :
        labSocketState->setText(QStringLiteral("socket状态:ListeningState"));
        break;
    case QAbstractSocket::ClosingState      :
        labSocketState->setText(QStringLiteral("socket状态:ClosingState"));
        break;
    }
}

void TcpServer::onClientConnected()
{
    // 客户端接入
    ui->plainTextEdit->appendPlainText("**client socket connected.");
    ui->plainTextEdit->appendPlainText("**peer address: " + tcpSocket->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("**peer port:" + QString::number(tcpSocket->peerPort()));
}

void TcpServer::onClientDisconnected()
{
    // 客户端断开连接
    ui->plainTextEdit->appendPlainText("**client disconnected.");
    tcpSocket->deleteLater();
}

void TcpServer::onSocketReadyRead()
{
    // 读取缓冲区行文本
    while(tcpSocket->canReadLine())
    {
        ui->plainTextEdit->appendPlainText("[in] " + tcpSocket->readLine());
    }
}

void TcpServer::onStartListenAct()
{
    // 开始监听
    // IP地址
    QString ip = ui->ipCombo->currentText();
    // 端口
    quint16 port = ui->port->value();

    QHostAddress addr(ip);

    // 开始监听
    tcpServer->listen(addr, port);

    ui->plainTextEdit->appendPlainText(QStringLiteral("**开始监听..."));
    ui->plainTextEdit->appendPlainText(QStringLiteral("**服务器地址:") + tcpServer->serverAddress().toString());
    ui->plainTextEdit->appendPlainText(QStringLiteral("**服务器端口:") + QString::number(tcpServer->serverPort()));

    startListenAct->setEnabled(false);
    stopListenAct->setEnabled(true);
    labListen->setText(QStringLiteral("监听状态:正在监听"));
}

void TcpServer::onStopListenAct()
{
    // 停止监听
    // tcpServer正在监听
    if(tcpServer->isListening())
    {
        // 停止监听
        tcpServer->close();
        startListenAct->setEnabled(true);
        stopListenAct->setEnabled(false);
        labListen->setText(QStringLiteral("监听状态:已停止监听"));
    }
}

void TcpServer::onClearAct()
{
    ui->plainTextEdit->clear();
}

void TcpServer::onQuitAct()
{
    this->close();
}


void TcpServer::on_btnSend_clicked()
{
    // 发送一行数据，以换行符结束
    QString msg = ui->edtSend->text();
    ui->plainTextEdit->appendPlainText("[out] " + msg);
    ui->edtSend->clear();
    ui->edtSend->setFocus();
    QByteArray str = msg.toUtf8();
    // 添加一个换行符
    str.append('\n');
    tcpSocket->write(str);
}
